/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including but not limited to the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to provide persons with access to the Software
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGE OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import { BreakpointManager } from '../../hooks/breakpoint';
import { getbreakpointManager } from '../../types/breakpoint';
import { AttributeManager } from '../../hooks/attributeManager';
import { EventManager } from '../../hooks/eventManager';
import { defaultConfig } from './default';

/**
 * @description 基于web components实现栅格组件父标签
 */
export class GridRowComponent extends HTMLElement {
  private _property: string[];
  private _elementId: string;
  private _styleElement: HTMLStyleElement | null;
  private _unsubscribeBreakpoint: () => void;
  private _attributeManager: AttributeManager;
  private _eventManager: EventManager;
  private _breakpointManager: BreakpointManager | null;
  private _observe: MutationObserver | null;
  private _customEvent: CustomEvent | null;
  private _mountedCustomEvent: CustomEvent | null;

  constructor() {
    super();
    this._styleElement = null;
    this._property = ['scope', 'columns', 'gutterX', 'gutterY', 'direction', 'breakpointValue', 'breakpointRefrence'];
    this._elementId = '';
    this._attributeManager = new AttributeManager();
    this._eventManager = new EventManager(this);
    this._breakpointManager = null;
    this._unsubscribeBreakpoint = () => {};
    this._observe = null;
    this._customEvent = null;
    this._mountedCustomEvent = null;
  }

  connectedCallback(): void {
    this._observe = new MutationObserver((mutations) => {
      let count = 0;
      mutations.forEach(item => {
        if (count === 0) {
          count ++;
          this._attachStyles();
        }
      })
    })
    if (this.children && this.children.length) {
      const children = Array.from(this.children) as HTMLElement[];
      children.forEach(element => {
        this._observe?.observe(element, {attributes: true});
      });
    }

    this._customEvent = new CustomEvent('calculatePosition', {
      detail: {message: true},
      bubbles: true,
      composed: true,
    });

    this._mountedCustomEvent = new CustomEvent('gridRowMounted', {
      detail: {message: true},
      bubbles: true,
      composed: true,
    });
    this.dispatchEvent(this._mountedCustomEvent);
  }

  disconnectedCallback(): void {
    this._unsubscribeBreakpoint();
  }

  static get observedAttributes(): string[] {
    return ['scope', 'columns', 'gutterX', 'gutterY', 'direction', 'breakpointValue', 'breakpointRefrence'];
  }

  attributeChangedCallback(name: string, oldValue: any, newValue: any): void {
    if (this._property.includes(name) && oldValue !== newValue) {
      this._attachStyles();
    }
  }

  private _attachStyles(): void {
    if (this._styleElement) {
      this._styleElement.remove();
    }

    const scopeId = this.getAttribute('scope') || '';
    if (scopeId && !this._breakpointManager) {
      this._elementId = scopeId;
      const breakpointValue = this.getAttribute('breakpointValue') || defaultConfig.container.breakpointValue;
      let rowBreakpoints = null;
      if (breakpointValue && typeof breakpointValue === 'string') {
        rowBreakpoints = JSON.parse(breakpointValue);
      }
      const breakpointRefrence = this.getAttribute('breakpointRefrence') || defaultConfig.container.breakpointRefrence;

      this._breakpointManager = getbreakpointManager(breakpointRefrence, rowBreakpoints, scopeId);
      this._unsubscribeBreakpoint = this._breakpointManager.subscribeToBreakpoint(() => {
        this._attachStyles();
      });
    }

    const columns = this.getAttribute('columns') || defaultConfig.container.columns;
    const gutterX = this._attributeManager.processSize(this.getAttribute('gutterX'), defaultConfig.container.gutterX);
    const gutterY = this._attributeManager.processSize(this.getAttribute('gutterY'), defaultConfig.container.gutterY);
    const direction = this._attributeManager.processMultiValues(this.getAttribute('direction'), ['row', 'row-reverse'], [], defaultConfig.container.direction);
    
    const style = document.createElement('style') as HTMLStyleElement;
    style.textContent = `
      .${scopeId} {
        display: grid;
        grid-template-columns: repeat(${columns}, 1fr);
        grid-auto-rows: auto;
        gap: ${gutterY} ${gutterX};
        direction: ${direction === 'row' ? 'ltr' : 'rtl'};
        width: 100%;
        height: 100%;
      }
    `;
    this._styleElement = style;
    document.head.appendChild(style);

    // 计算按order排序后各组件的位置
    if (this._elementId) {
      requestAnimationFrame(() => {
        this.calChildElementPositions(columns);
      });
      if (this._customEvent) {
        this.dispatchEvent(this._customEvent);
      }
    }
    
  }

  calChildElementPositions(columns: string | number): void {
    const parentElement = document.querySelector(`.${this._elementId}`);
    if (parentElement) {
      // 1. 获取所有子元素
      const children = Array.from(parentElement.children) as HTMLElement[];
      // 2. 按 order 属性排序
      const sortedChildren = children.sort((a, b) => {
        let orderA = parseInt(a.getAttribute('order') ?? '0') || 0;
        let orderB = parseInt(b.getAttribute('order') ?? '0') || 0;
        orderA = orderA < 0 ? 0 : orderA;
        orderB = orderB < 0 ? 0 : orderB;
        return orderA - orderB;
      });
      // 3. 计算元素位置
      let remainingWidth = Number(columns);
      let gridColumnStart = 1;
      let gridColumnEnd = 1;
      let gridRowStart = 1;
      let gridRowEnd = 1;
      sortedChildren.forEach((children, index) => {
        let offset = parseInt(children.getAttribute('offset') ?? '0');
        let span = parseInt(children.getAttribute('span') ?? '1');
        span = span > Number(columns) ? Number(columns) : span < 0 ? 1 : span;
        offset = offset < 0 ? 0 : offset;
        if (index == 0) {
          if (span + offset >  Number(columns)) {
            gridColumnStart = 1;
          } else {
            gridColumnStart = offset + 1;
          }
        } else {
          if (offset == 0) {
            if (remainingWidth >= span) { // 表示该组件和前一个组件在同一行布局。
              gridColumnStart = gridColumnEnd;
            } else {
              gridColumnStart = 1;
              gridRowStart += 1;
            }
          } else {
            if (remainingWidth >= offset + span) { // 表示该组件和前一个组件在同一行布局。
              gridColumnStart = gridColumnEnd + offset;
            } else { // 表示该组件和前一个组件在不同行布局
              if (offset < remainingWidth) { // 表示该组件的偏移量小于上一行遗留的位置，因此该组件会在该行起始位置开始布局。
                gridColumnStart = 1;
                gridRowStart = gridRowStart + 1;
              } else {
                while ( Number(columns) < offset - remainingWidth) {
                  offset -= Number(columns);
                }
                if ( Number(columns) - (offset - remainingWidth) >= span) {
                  gridColumnStart = offset - remainingWidth + 1;
                  gridRowStart += 1;
                } else {
                  gridColumnStart = 1;
                  gridRowStart += 1;
                }
              }
            }
          }
        }
        gridRowEnd = gridRowStart + 1;
        gridColumnEnd = gridColumnStart + span;
        remainingWidth = Number(columns) - gridColumnEnd + 1;
        children.style.setProperty('--gridColumnStart', gridColumnStart + '');
        children.style.setProperty('--gridColumnEnd', gridColumnEnd + '');
        children.style.setProperty('--gridRowStart', gridRowStart + '');
        children.style.setProperty('--gridRowEnd', gridRowEnd + '');
      });
    }
  }

  registerEvents(callback: (param: any) => void): void {
    if (this._elementId) {
      const gridInstance = document.querySelectorAll(`*[scope=${this._elementId}]`);
      const gridItems = gridInstance[0].querySelectorAll('grid-col');
      if (gridItems.length) {
        gridItems.forEach((item, index) => {
          item.addEventListener('click', (e) => {
            e.preventDefault();
            this._eventManager.emit('gridColClick', {
              index,
              name: item.getAttribute('name') || '',
            });
          });
        });
        this._eventManager.on('gridColClick', callback);
      }
    }
  }
}

if (!customElements.get('grid-row')) {
  customElements.define('grid-row', GridRowComponent);
}
